package test;

import java.util.HashMap;
import java.util.Map;

/**
 * 测试报文结构分析工具类
 */
public class SL651TestMessageAnalysis {
    private static final Map<String, String> ELEMENT_UNIT_MAP = new HashMap<>();
    static {
        ELEMENT_UNIT_MAP.put("20", "mm"); // 当前降水量
        ELEMENT_UNIT_MAP.put("26", "mm"); // 降水量累计值
        ELEMENT_UNIT_MAP.put("39", "m");  // 瞬时河道水位
        ELEMENT_UNIT_MAP.put("38", "V");  // 电源电压
    }
    
    public static void main(String[] args) {
        // 测试报文（上行）
        String uplinkMessage = "7E7E010012345678123430002B020003591011154947F1F1001234567848F0F0591011154920190000052619000005392300000127381211150320FA";
        
        System.out.println("测试报文结构分析:");
        System.out.println("完整报文: " + uplinkMessage);
        System.out.println("报文长度: " + uplinkMessage.length() + " 字符");
        System.out.println();
        
        // 按字段解析
        int pos = 0;
        
        // 1. 帧起始符 (4字符)
        String frameStart = uplinkMessage.substring(pos, pos + 4);
        System.out.println("[" + pos + "-" + (pos+3) + "] 帧起始符: " + frameStart);
        pos += 4;
        
        // 2. 中心站地址 (2字符)
        String centerAddr = uplinkMessage.substring(pos, pos + 2);
        System.out.println("[" + pos + "-" + (pos+1) + "] 中心站地址: " + centerAddr);
        pos += 2;
        
        // 3. 遥测站地址 (10字符)
        String stationAddr = uplinkMessage.substring(pos, pos + 10);
        System.out.println("[" + pos + "-" + (pos+9) + "] 遥测站地址: " + stationAddr);
        pos += 10;
        
        // 4. 密码 (4字符)
        String password = uplinkMessage.substring(pos, pos + 4);
        System.out.println("[" + pos + "-" + (pos+3) + "] 密码: " + password);
        pos += 4;
        
        // 5. 功能码 (2字符)
        String functionCode = uplinkMessage.substring(pos, pos + 2);
        System.out.println("[" + pos + "-" + (pos+1) + "] 功能码: " + functionCode + " (测试报文)");
        pos += 2;
        
        // 6. 标识符和长度 (4字符)
        String flagAndLength = uplinkMessage.substring(pos, pos + 4);
        System.out.println("[" + pos + "-" + (pos+3) + "] 标识符和长度: " + flagAndLength);
        pos += 4;
        
        // 7. 数据起始符STX (2字符)
        String stx = uplinkMessage.substring(pos, pos + 2);
        System.out.println("[" + pos + "-" + (pos+1) + "] 数据起始符STX: " + stx);
        pos += 2;
        
        // 8. 流水号 (4字符)
        String serialNumber = uplinkMessage.substring(pos, pos + 4);
        System.out.println("[" + pos + "-" + (pos+3) + "] 流水号: " + serialNumber);
        pos += 4;
        
        // 9. 发报时间 (12字符)
        String reportTime = uplinkMessage.substring(pos, pos + 12);
        System.out.println("[" + pos + "-" + (pos+11) + "] 发报时间: " + reportTime);
        pos += 12;
        
        // 10. 数据段开始
        System.out.println("[" + pos + "-...] 数据段:");
        
        // 解析数据段
        String dataSegment = uplinkMessage.substring(pos, uplinkMessage.length() - 6); // 减去ETX(2) + CRC(4)
        System.out.println("  数据段内容: " + dataSegment);
        System.out.println("  数据段长度: " + dataSegment.length() + " 字符");
        System.out.println();
        
        // 按标识符解析数据段
        parseDataSegment(dataSegment);
        
        // 11. 数据结束符ETX (2字符)
        String etx = uplinkMessage.substring(uplinkMessage.length() - 6, uplinkMessage.length() - 4);
        System.out.println("[" + (uplinkMessage.length() - 6) + "-" + (uplinkMessage.length() - 5) + "] 数据结束符ETX: " + etx);
        
        // 12. CRC校验码 (4字符)
        String crc = uplinkMessage.substring(uplinkMessage.length() - 4);
        System.out.println("[" + (uplinkMessage.length() - 4) + "-" + (uplinkMessage.length() - 1) + "] CRC校验码: " + crc);
    }
    
    /**
     * 解析数据段内容
     */
    private static void parseDataSegment(String dataSegment) {
        System.out.println("数据段详细解析:");
        int pos = 0;
        int elementIndex = 0;
        
        while (pos < dataSegment.length()) {
            elementIndex++;
            System.out.print("  元素 " + elementIndex + ": ");
            
            // 检查是否还有足够的字符来读取标识符（2字节，4个HEX字符）
            if (pos + 4 > dataSegment.length()) {
                System.out.println("剩余字符不足: " + dataSegment.substring(pos));
                break;
            }
            
            // 读取2字节标识符（4个HEX字符）
            String identifier = dataSegment.substring(pos, pos + 4);
            System.out.print(identifier + " ");
            pos += 4;
            
            // 解析标识符的高位字节和低位字节
            String highByte = identifier.substring(0, 2);
            String lowByte = identifier.substring(2, 4);
            
            // 根据标识符类型处理
            switch (highByte.toUpperCase()) {
                case "F1": // 地址标识符  遥测站地址与遥测 站分类码是固定组合
                    System.out.print("地址标识符 ");
                    if (pos + 12 <= dataSegment.length()) {
                        String address = dataSegment.substring(pos, pos + 12);
                        System.out.println("遥测站地址=" + address);
                        pos += 12;
                    } else {
                        System.out.println("数据不足");
                    }
                    break;
                    
                case "F0": // 观测时间标识符
                    System.out.print("观测时间标识符 ");
                    if (pos + 10 <= dataSegment.length()) {
                        String time = dataSegment.substring(pos, pos + 10);
                        System.out.println("观测时间=" + time);
                        pos += 10;
                    } else {
                        System.out.println("数据不足");
                    }
                    break;
                    
                case "20": // 当前降水量标识符
                    System.out.print("当前降水量标识符 ");
                    pos = parseElementData(dataSegment, pos, lowByte, "当前降水量", "mm");
                    break;
                    
                case "26": // 降水量累计值标识符
                    System.out.print("降水量累计值标识符 ");
                    pos = parseElementData(dataSegment, pos, lowByte, "累计降水量", "mm");
                    break;
                    
                case "39": // 水位标识符
                    System.out.print("水位标识符 ");
                    pos = parseElementData(dataSegment, pos, lowByte, "水位", "m");
                    break;
                    
                case "38": // 电压标识符
                    System.out.print("电压标识符 ");
                    pos = parseElementData(dataSegment, pos, lowByte, "电压", "V");
                    break;
                    
                default:
                    System.out.println("未知标识符");
                    // 尝试跳过一些字符继续解析
                    if (pos + 4 <= dataSegment.length()) {
                        pos += 4;
                    } else {
                        pos = dataSegment.length();
                    }
                    break;
            }
        }
    }
    
    /**
     * 公共方法：解析元素数据
     * @param dataSegment 数据段
     * @param pos 当前位置
     * @param lowByte 低位字节
     * @param elementName 元素名称
     * @param unit 单位
     * @return 解析后的新位置
     */
    private static int parseElementData(String dataSegment, int pos, String lowByte, String elementName, String unit) {
        try {
            // 低位字节的高4位表示数据字节数，低4位表示小数点后位数
            int lowByteValue = Integer.parseInt(lowByte, 16);
            int dataBytes = (lowByteValue >> 4) & 0x0F;  // 高4位
            int decimalPlaces = lowByteValue & 0x0F;     // 低4位
            System.out.print("(字节数=" + dataBytes + ", 小数位=" + decimalPlaces + ") ");
            
            if (pos + (dataBytes * 2) <= dataSegment.length()) {
                String valueHex = dataSegment.substring(pos, pos + (dataBytes * 2));
                
                // 将十六进制数值转换为十进制
                long valueDecimal = parseBcdValue(valueHex);
                
                // 计算实际数值（除以10的小数位次方）
                double actualValue = valueDecimal / Math.pow(10, decimalPlaces);
                
                // 格式化输出（保留对应小数位）
                String format = "%." + decimalPlaces + "f%s";
                System.out.println(elementName + "=" + String.format(format, actualValue, unit));
                
                // 返回更新后的位置
                return pos + (dataBytes * 2);
            } else {
                System.out.println("数据不足");
                return pos;
            }
        } catch (Exception e) {
            System.out.println("解析失败: " + e.getMessage());
            return pos;
        }
    }
    
    /**
     * 将BCD编码的十六进制字符串解析为十进制数值
     * BCD编码中每个十六进制字符代表一个十进制数字
     * 例如："1234" 表示十进制数 1234
     */
    private static long parseBcdValue(String hexValue) {
        long result = 0;
        for (int i = 0; i < hexValue.length(); i++) {
            char c = hexValue.charAt(i);
            int digit;
            if (c >= '0' && c <= '9') {
                digit = c - '0';
            } else if (c >= 'A' && c <= 'F') {
                digit = c - 'A' + 10;
            } else {
                throw new NumberFormatException("Invalid hex character: " + c);
            }
            result = result * 10 + digit;
        }
        return result;
    }
}